package com.sebscape.sebcms.tools;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;
import java.text.SimpleDateFormat;

public class CalendarCreator
{

    private static Log log = LogFactory.getLog(CalendarCreator.class);

    private int dayWeekBegins = Calendar.SUNDAY;

    public int getDayWeekBegins() {
        return dayWeekBegins;
    }

    public void setDayWeekBegins(int dayWeekBegins) {
        this.dayWeekBegins = dayWeekBegins;
    }

    public CalendarCreator() {
    }

    public CalendarCreator( int dayWeekBegins ) {
        this.setDayWeekBegins( dayWeekBegins );
    }

    public static void main(String[] args) {
        Calendar cal = new GregorianCalendar( 2005, 10, 21);
        CalendarCreator cc = new CalendarCreator();
        SbCalendar sbc = cc.getSbCalendar( cal.getTime(), null);
        // loop thru weeks
        List<SbWeek> weeks = sbc.getWeekList();
        for ( int i = 0; i < weeks.size(); i++ ){
            SbWeek week = weeks.get( i );
            log.debug("week - " + i );
            // loop thru days.
            List<SbDay> days = week.getDayList();
            for ( int j = 0; j < days.size(); j++ ){
                SbDay day = (SbDay)days.get( j );
                log.debug(" +--- day - " + j + " ( " + day.getFocused() + " ) - " +
                        new SimpleDateFormat( "MM/dd/yyyy").format( day.getDate() ) );
            }
        }
    }

    private int computeLastDateOfMonth( Date date ){
        Calendar calendar = new GregorianCalendar();
        calendar.setTime( DateUtils.getLastDateOfMonth( date, false ) );
        return calendar.get( Calendar.DAY_OF_MONTH );
    }

    private int computeDayMonthBegins( Date date ){
        Calendar calendar = new GregorianCalendar();
        calendar.setTime( DateUtils.getFirstDateOfMonth( date, false ) );
        return DateUtils.dayOfWeekShifter( calendar.get( Calendar.DAY_OF_WEEK ), this.dayWeekBegins );
    }

    public SbCalendar getSbCalendar( Date pivotDate, Map<Date, List<Object>> eventMap )
    {
        log.debug("Begin getSbCalendar...");
        log.debug("pivotDate = " + pivotDate);
        if( eventMap != null ){
            log.debug("eventMap.size() = " + eventMap.size());
        } else {
            log.debug( "eventMap = null" );
        }
        int dayMonthBegins = computeDayMonthBegins( pivotDate );
        int lastDateOfMonth = computeLastDateOfMonth( pivotDate );
        Calendar gregorian = new GregorianCalendar();
        gregorian.setTime( pivotDate );
        SbCalendar sbCalendar = new SbCalendar();
        sbCalendar.setPivotDate( pivotDate );
        SbWeek sbWeek = new SbWeek();
        // Create the first week. This is different in that there may be some days listed from the previous month.
        Calendar prevCalendar = new GregorianCalendar();
        prevCalendar.setTime( DateUtils.getFirstDateOfMonth( gregorian.getTime(), false ) );
        prevCalendar.add( Calendar.DATE, 0 - dayMonthBegins );
        int dayOfWeek = 0;
        for ( int x = Calendar.SUNDAY; x < dayMonthBegins; x++ )
        // blank boxes for days of previous month. ie, if month starts on Tues, Sun-Mon are blank
        {
            prevCalendar.add( Calendar.DATE, 1 );
            SbDay sbDay = new SbDay( Boolean.FALSE, prevCalendar.getTime(), null );
            sbWeek.getDayList().add( sbDay );
        }
        // Complete the first Week.
        int dayOfMonth = 1;
        for ( dayOfWeek = dayMonthBegins; dayOfWeek <= Calendar.SATURDAY; dayOfWeek++ )
        // blank boxes for days of previous month. ie, if month starts on Tues, Sun-Mon are blank
        {
            gregorian.set( Calendar.DAY_OF_MONTH, dayOfMonth++ );
            List<Object>  eventList = null;
            try {
                log.debug("Check Map using: " + DateUtils.getDayBegin( gregorian.getTime() ) );
                if( eventMap != null ){
                    eventList = (List<Object> )eventMap.get( DateUtils.getDayBegin( gregorian.getTime() ) );
                }
                if ( eventList != null )
                     log.debug("This day has events.size = " + eventList.size() );
            } catch (Exception e) {
                log.error( e );
            }
            sbWeek.getDayList().add( new SbDay( Boolean.TRUE, gregorian.getTime(), eventList ) );
        }
        sbCalendar.getWeekList().add(sbWeek);
        // The actual calendar
        sbWeek = new SbWeek();
        for ( ; dayOfMonth <= lastDateOfMonth; dayOfMonth++ )
        {
            if ( dayOfWeek >= 7 )
            {
                sbCalendar.getWeekList().add(sbWeek);
                sbWeek = new SbWeek();
                dayOfWeek = 1;
            }
            else
            {
                dayOfWeek++;
            }
            gregorian.set( Calendar.DAY_OF_MONTH, dayOfMonth );
            List<Object>  eventList = null;
            try {
                log.debug("Check Map using: " + DateUtils.getDayBegin( gregorian.getTime() ) );
                if( eventMap != null ){
                    eventList = (List<Object>)eventMap.get( DateUtils.getDayBegin( gregorian.getTime() ) );
                }
                if ( eventList != null )
                     log.debug("This day has events.size = " + eventList.size() );
            } catch (Exception e) {
                log.error( e );
            }
            sbWeek.getDayList().add( new SbDay( Boolean.TRUE, gregorian.getTime(), eventList ) );
        }
        // round out the last week.
        while( dayOfWeek++ < 7 ){
            gregorian.add( Calendar.DATE, 1);
            sbWeek.getDayList().add( new SbDay( Boolean.FALSE, gregorian.getTime(), null ) );
        }
        sbCalendar.getWeekList().add( sbWeek );
        return sbCalendar;
    }

    public class SbCalendar{
        private Date pivotDate;
        private List<SbWeek> weekList = new ArrayList<SbWeek>();

        public SbCalendar() {}
        public SbCalendar( Date pivotDate, List<SbWeek> weekList ){
            this.setPivotDate( pivotDate );
            this.setWeekList( weekList );
        }

        public Date getPivotDate() {
            return pivotDate;
        }

        public void setPivotDate(Date pivotDate) {
            this.pivotDate = pivotDate;
        }

        public List<SbWeek> getWeekList() {
            return weekList;
        }

        public void setWeekList(List<SbWeek> weekList) {
            this.weekList = weekList;
        }
    }

    public class SbWeek {
        private List<SbDay> dayList = new ArrayList<SbDay>();
        public SbWeek() {}
        public SbWeek( List<SbDay> dayList ){ this.setDayList( dayList ); }

        public List<SbDay> getDayList() {
            return dayList;
        }

        public void setDayList(List<SbDay> dayList) {
            this.dayList = dayList;
        }
    }

    public class SbDay {
        private Boolean focused;
        private Date date;
        private List<Object> events = new ArrayList<Object> ();

        public SbDay(){}
        public SbDay( Boolean isFocused, Date date, List<Object>  eventList ){
            this.setFocused( isFocused );
            this.setDate( date );
            this.setEvents( eventList );
        }
        public Boolean getFocused() {
            return focused;
        }

        public void setFocused(Boolean focused) {
            this.focused = focused;
        }

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            this.date = date;
        }

        public List<Object>  getEvents() {
            return events;
        }

        public void setEvents(List<Object>  events) {
            this.events = events;
        }

    }

}